﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Security.Cryptography;
using System.Diagnostics;
using System.Net.NetworkInformation;

namespace GMA_SERVICE
{
    public partial class gmasvc : ServiceBase
    {
        public static int __port = 0;
        public static string __passwd = string.Empty;
        public static string __dns = string.Empty;
        public static bool __lock = true;
        public static Socket s;

        public gmasvc()
        {
            InitializeComponent();
            this.ServiceName = "GMAQUERRY";
            this.EventLog.Log = "Application";
            this.CanHandlePowerEvent = true;
            this.CanHandleSessionChangeEvent = true;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;
            this.CanStop = true;
            
        }

        protected override void OnStart(string[] args)
        {
            __Startup();
        }

        protected override void OnStop()
        {
            base.OnStop();
            try
            {
                s.Close();
            }
            catch (Exception ex)
            {

            }
        }



        /*------------------------------*/

        public static void __Startup()
        {
            Console.ForegroundColor = System.ConsoleColor.Green;
            __load_config();

            Console.WriteLine("The server is running at {0} port {1}...", __port.ToString(), __dns);
            Console.WriteLine("Waiting for a connection.....");
        L001:
            try
            {
                IPAddress ipAd = IPAddress.Parse(__dns);
                TcpListener newList = new TcpListener(ipAd, __port);
                newList.Start();
                s = newList.AcceptSocket();
                Console.WriteLine("Remote accepted from " + s.RemoteEndPoint);

                byte[] b = new byte[5000];
                //byte[] b = null;
                int k = 0;
                try
                {
                    k = s.Receive(b);
                }
                catch (Exception ex)
                {
                    s.Close();
                    newList.Stop();
                    goto L001;
                }
                Console.WriteLine("Recieved...");
                StringBuilder bd = new StringBuilder();
                for (int i = 0; i < k; i++)
                {
                    bd.Append(Convert.ToChar(b[i]).ToString());
                }
                Console.WriteLine("Command => " + bd.ToString());

                Console.WriteLine("\r\nThe byte data is: ");
                for (int i = 0; i < k; i++)
                    Console.Write(b[i]);

                ASCIIEncoding asen = new ASCIIEncoding();
                s.Send(asen.GetBytes(__Command_lib(bd.ToString())));

                NetworkStream nts = new NetworkStream(s);
                StreamReader strea = new StreamReader(nts);
                StreamWriter strwri = new StreamWriter(nts);

                string output;
                output = strea.ReadLine();
                Console.WriteLine("\r\nReturn info => " + output);


                s.Close();
                newList.Stop();
                //goto L001;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error => " + ex.Message + Environment.NewLine);
                goto L001;
            }

            goto L001;


        }

        public static void __load_config()
        {
            if (File.Exists("config.sys"))
            {
                string[] avdns = get_text_file("config.sys").Split(':');
                __dns = avdns[0];
                __port = Convert.ToInt32(avdns[1]);
            }
            else
            {
                __dns = GetIP();
                __port = 7777;
            }


            if (File.Exists("secrets.sys"))
            {
                __passwd = get_text_file("secrets.sys");

            }
            else
            {
                __passwd = Encrypt("NILL");
            }
        }

        public static string __Command_lib(string __cmd)
        {
            string __msg_notlogin = "Sorry, you're not login!";

            try
            {
                string[] tmp = __cmd.Split(' ');
                string cmd = tmp[0];
                string param = tmp[1];

                switch (cmd)
                {
                    case "cmd":
                        {
                            if (__login())
                            {
                                Console.WriteLine("Execute param => " + param.Replace("_", " ").Replace(":", ":\\").Replace("*", "."));
                                string __result = ExecuteCommandSync(param.Replace("_", " ").Replace(":", ":\\").Replace("*", "."));
                                return "Result =>\r\n" + __result;
                            }
                            else
                            {
                                return __msg_notlogin;
                            }

                        }
                    case "login":
                        {
                            __load_config();
                            if (Decrypt(__passwd).Trim() == param.Trim())
                            {
                                __lock = false;
                                string[] rempip = s.RemoteEndPoint.ToString().Split(':');
                                writetext("session.sys", Encrypt(rempip[0] + " " + DateTime.Now.ToString().Replace(" ", "_") + " " + __passwd));

                                return "New session has been add\r\n" + rempip[0] + " " + DateTime.Now;
                            }
                            else
                            {
                                return "Sorry, password was wrong!";
                            }
                        }
                    case "passwd":
                        {

                            if (__login() && !__lock)
                            {
                                writetext("secrets.sys", Encrypt(param.Trim()));
                                __lock = true;
                                __load_config();
                                return "Password has been change!";
                            }
                            else
                            {
                                return __msg_notlogin;
                            }

                        }
                    case "logout":
                        {
                            if (__login())
                            {
                                __lock = true;
                                writetext("session.sys", string.Empty);
                                return "Server has been logout!";
                            }
                            else
                            {
                                return __msg_notlogin;
                            }

                        }
                    case "session":
                        {
                            if (__login())
                            {
                                return Decrypt(get_text_file("session.sys"));
                            }
                            else
                            {
                                return __msg_notlogin;
                            }
                        }
                    case "proc":
                        {
                            Process[] processlist = Process.GetProcesses();
                            string __proc = "";
                            foreach (Process theprocess in processlist)
                            {
                                __proc += "Process: " + theprocess.ProcessName + " ID: " + theprocess.Id + Environment.NewLine;
                            }
                            return __proc;
                        }
                    default:
                        {
                            return "This command not found in lib!";
                        }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return "NULL command!";
            }
        }

        #region interface
        public static bool __login()
        {

            try
            {
                string[] logininf = Decrypt(get_text_file("session.sys")).Split(' ');
                string[] remip = s.RemoteEndPoint.ToString().Split(':');
                string intime = logininf[1].Replace("_", " ");
                DateTime inptime = DateTime.Parse(intime);
                TimeSpan expart = DateTime.Now - inptime;
                Console.WriteLine(logininf[0]);
                if (expart.Minutes > 30 && remip[0] != logininf[0])
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }


        #endregion

        #region Diagam base

        public static string ExecuteCommandSync(object command)
        {
            string avm = "NULL";
            try
            {
                ProcessStartInfo start = new ProcessStartInfo("cmd", "/c " + command);
                //start.FileName = @"C:\7za.exe"; // Specify exe name.
                start.UseShellExecute = false;
                start.RedirectStandardOutput = true;

                using (Process process = Process.Start(start))
                {
                    using (StreamReader reader = process.StandardOutput)
                    {
                        string result = reader.ReadToEnd();
                        avm = result;
                    }
                }
                return avm;
            }
            catch (Exception ex)
            {
                return "Run CMD -> " + ex.Message;
            }
        }

        public static string LocalIPAddress()
        {
            IPHostEntry host;
            string localIP = "";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIP = ip.ToString();
                    break;
                }
            }
            return localIP;
        }

        public static string Encrypt(string clearText)
        {
            string EncryptionKey = "MAKV2SPBNI99212**@#^%^^&^$$^&&$#&(*&^#$$&*($&%*&($";
            byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new
                    Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(clearBytes, 0, clearBytes.Length);
                        cs.Close();
                    }
                    clearText = Convert.ToBase64String(ms.ToArray());
                }
            }
            return clearText;
        }

        public static string Decrypt(string cipherText)
        {
            string EncryptionKey = "MAKV2SPBNI99212**@#^%^^&^$$^&&$#&(*&^#$$&*($&%*&($";
            byte[] cipherBytes = Convert.FromBase64String(cipherText);
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new
                    Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.Close();
                    }
                    cipherText = Encoding.Unicode.GetString(ms.ToArray());
                }
            }
            return cipherText;
        }

        public static void writetext(string path, string lines)
        {
            try
            {
                TextWriter tsw = new StreamWriter(path);

                tsw.WriteLine(lines);
                tsw.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public static string get_text_file(string path)
        {
            try
            {
                using (TextReader reader = File.OpenText(path))
                {
                    string line = reader.ReadToEnd();
                    reader.Close();
                    return line;
                }
            }
            catch (Exception ex)
            {

                return "";
            }
        }

        public static string GetIP()
        {
            IPHostEntry host;
            string localIP = "";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily.ToString() == "InterNetwork")
                {
                    return ip.ToString();
                }
            }
            return localIP;
        }

        #endregion




    }
}
